package linker

// this file contains input file apis things
import (
	"debug/elf"
	"fmt"
	"rvld/src/utils"
)

func NewInputFile(file *File) InputFile {
	f := InputFile{File: file}
	if len(file.Contents) < EhdrSize {
		utils.ThisFatal("[ERROR]: file too small, less than EhdrSize")
	}

	if !CheckMagic(file.Contents) {
		utils.ThisFatal("[ERROR]: the provided file is not an `ELF` file")
	}

	ehdr := utils.ThisRead[Ehdr](file.Contents)
	contents := file.Contents[ehdr.ShOff:]
	shdr := utils.ThisRead[Shdr](contents)

	numSections := int64(ehdr.ShNum)
	if numSections == 0 {
		numSections = int64(shdr.Size)
	}

	f.ElfSections = []Shdr{shdr}
	for numSections > 1 {
		contents = contents[ShdrSize:]
		f.ElfSections = append(f.ElfSections, utils.ThisRead[Shdr](contents))
		numSections--
	}

	shstrndx := int64(ehdr.ShStrndx)
	if ehdr.ShStrndx == uint16(elf.SHN_XINDEX) {
		shstrndx = int64(shdr.Link)
	}

	f.ShStrtab = f.GetBytesFromIdx(shstrndx)
	return f
}

func (f *InputFile) GetBytesFromIdx(idx int64) []byte {
	return f.GetBytesFromShdr(&f.ElfSections[idx])
}

func (f *InputFile) GetBytesFromShdr(s *Shdr) []byte {
	end := s.Offset + s.Size
	if uint64(len(f.File.Contents)) < end {
		utils.ThisFatal(
			fmt.Sprintf("[ERROR]: section header is out of range: %d", s.Offset),
		)
	}

	return f.File.Contents[s.Offset:end]
}

func (f *InputFile) FillUpElfSyms(s *Shdr) {
	bs := f.GetBytesFromShdr(s)
	f.ElfSyms = utils.ThisReadSlice[Sym](bs, SymSize)
}

func (f *InputFile) FindSection(ty uint32) *Shdr {
	for i := 0; i < len(f.ElfSections); i++ {
		shdr := &f.ElfSections[i]
		if shdr.Type == ty {
			return shdr
		}
	}

	return nil
}

func (f *InputFile) GetEhdr() Ehdr {
	return utils.ThisRead[Ehdr](f.File.Contents)
}

// DONE
